package com.ht.api.db.hlink;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

public class JsonTreeProcessor {

    @Data
    @Getter
    @Setter
    public static class JsonTreeNode {
        private String key;
        private String path;
        private Object value;
        private boolean isArray;
        private List<JsonTreeNode> children = new ArrayList<>();

        public void setIsArray (boolean isArray) {
            this.isArray = isArray;
        }
    }

    @Data
    private static class PathValue {
        private Object value;
        private List<Integer> indices = new ArrayList<>();

        public PathValue(Object value, List<Integer> indices) {
            this.value = value;
            this.indices.addAll(indices);
        }
    }

    /**
     * JSON转树结构
     */
    public static JsonTreeNode parseJsonToTree(String json) {
        Object jsonObj = JSONUtil.parse(json);
        return buildTree("root", "$", jsonObj);
    }

    public static JSONObject treeToJson(JsonTreeNode node) {
        JSONObject json = new JSONObject();
        json.set("title", node.getKey());  // 节点显示的文本
        json.set("key", node.getPath());   // 节点的唯一标识

        // 添加其他可能需要的属性
        json.set("isLeaf", node.getChildren().isEmpty());  // 是否是叶子节点
        json.set("isArray", node.isArray());              // 是否是数组

        // 如果不是对象或数组，添加具体值
        if (!(node.getValue() instanceof JSONObject) &&
                !(node.getValue() instanceof JSONArray)) {
            json.set("value", node.getValue());
        }

        // 处理子节点
        if (!node.getChildren().isEmpty()) {
            JSONArray children = new JSONArray();
            for (JsonTreeNode child : node.getChildren()) {
                children.add(treeToJson(child));
            }
            json.set("children", children);
        }

        return json;
    }

    private static JsonTreeNode buildTree(String key, String path, Object node) {
        JsonTreeNode treeNode = new JsonTreeNode();
        treeNode.setKey(key);
        treeNode.setPath(path);

        if (node instanceof JSONArray) {
            JSONArray jsonArray = (JSONArray) node;
            treeNode.setIsArray(true);
            // 只处理数组的第一个元素
            if (jsonArray.size() > 0) {
                Object firstElement = jsonArray.get(0);
                if (firstElement instanceof JSONObject) {
                    JSONObject jsonObj = (JSONObject) firstElement;
                    jsonObj.forEach((k, v) -> {
                        treeNode.getChildren().add(
                                buildTree(k.toString(),
                                        path + "[*]." + k,
                                        v)
                        );
                    });
                }
            }
            treeNode.setValue(jsonArray);
        } else if (node instanceof JSONObject) {
            JSONObject jsonObj = (JSONObject) node;
            jsonObj.forEach((k, v) -> {
                treeNode.getChildren().add(
                        buildTree(k.toString(),
                                path + "." + k,
                                v)
                );
            });
            treeNode.setValue(jsonObj);
        } else {
            treeNode.setValue(node);
        }

        return treeNode;
    }

    /**
     * 根据一个Map，从一个json对象中提取值，最后返回一个json数组对象
     * @param json 原始的json数据对象
     * @param keyPaths 一个Map<K, V>，K为提取值后要放入json对象中的键值，V为提取值时对应的json结点路径，如：$.addresses[*].city
     * @return
     */
    public static JSONArray extractValuesToJsonArray(String json, Map<String, String> keyPaths) {
        return extractValuesToJsonArray(JSONUtil.parseObj(json), keyPaths);
    }
    
    /**
     * 根据一个Map，从一个json对象中提取值，最后返回一个json数组对象
     * @param rootObj json对象
     * @param keyPaths 一个Map<K, V>，K为提取值后要放入json对象中的键值，V为提取值时对应的json结点路径，如：$.addresses[*].city
     * @return
     */
    public static JSONArray extractValuesToJsonArray(JSONObject rootObj, Map<String, String> keyPaths) {
        // 检查是否包含数组路径
        boolean hasArrayPath = keyPaths.values().stream().anyMatch(path -> path.contains("[*]"));

        if (hasArrayPath) {
            return extractArrayValues(rootObj, keyPaths);
        } else {
            return extractSimpleValues(rootObj, keyPaths);
        }
    }

    private static JSONArray extractSimpleValues(JSONObject rootObj, Map<String, String> keyPaths) {
        JSONArray result = new JSONArray();
        JSONObject record = new JSONObject();

        // 处理简单对象的情况
        for (Map.Entry<String, String> entry : keyPaths.entrySet()) {
            String key = entry.getKey();
            String path = entry.getValue().replaceFirst("\\$\\.", "");
            List<PathValue> values = new ArrayList<>();
            extractValuesRecursive(rootObj, path.split("\\."), 0, values, new ArrayList<>());

            if (!values.isEmpty()) {
                record.set(key, values.get(0).getValue());
            } else {
                record.set(key, null);
            }
        }

        // 只有当至少有一个值不为null时才添加记录
        if (!record.isEmpty()) {
            result.add(record);
        }

        return result;
    }

    private static JSONArray extractArrayValues(JSONObject rootObj, Map<String, String> keyPaths) {
        // 存储每个路径的提取结果，包含值和对应的数组索引路径
        Map<String, List<PathValue>> pathValues = new HashMap<>();

        // 1. 提取所有路径的值和索引信息
        for (Map.Entry<String, String> entry : keyPaths.entrySet()) {
            String key = entry.getKey();
            String path = entry.getValue().replaceFirst("\\$\\.", "");
            List<PathValue> values = new ArrayList<>();
            extractValuesRecursive(rootObj, path.split("\\."), 0, values, new ArrayList<>());
            pathValues.put(key, values);
        }

        // 2. 找出最深层的数组路径作为基准
        String deepestArrayPath = null;
        int maxDepth = 0;
        for (Map.Entry<String, String> entry : keyPaths.entrySet()) {
            String path = entry.getValue();
            int depth = path.split("\\[\\*\\]").length - 1;
            if (depth > maxDepth) {
                maxDepth = depth;
                deepestArrayPath = entry.getKey();
            }
        }

        // 3. 构建结果数组
        JSONArray result = new JSONArray();
        if (deepestArrayPath != null) {
            List<PathValue> baseValues = pathValues.get(deepestArrayPath);

            for (PathValue baseValue : baseValues) {
                JSONObject record = new JSONObject();

                // 为每个路径找到匹配的值
                for (Map.Entry<String, String> entry : keyPaths.entrySet()) {
                    String key = entry.getKey();
                    List<PathValue> values = pathValues.get(key);

                    // 找到索引匹配的值
                    Object matchedValue = findMatchingValue(values, baseValue.getIndices());
                    record.set(key, matchedValue);
                }

                result.add(record);
            }
        }

        return result;
    }

    private static Object findMatchingValue(List<PathValue> values, List<Integer> targetIndices) {
        if (values == null || values.isEmpty()) {
            return null;
        }

        // 如果是非数组路径（只有一个值）
        if (values.size() == 1 && values.get(0).getIndices().isEmpty()) {
            return values.get(0).getValue();
        }

        // 查找索引匹配的值
        for (PathValue pv : values) {
            if (isIndicesMatch(pv.getIndices(), targetIndices)) {
                return pv.getValue();
            }
        }

        return null;
    }

    private static boolean isIndicesMatch(List<Integer> indices1, List<Integer> indices2) {
        // 检查较短的索引序列是否匹配较长索引序列的开头部分
        int minLength = Math.min(indices1.size(), indices2.size());
        for (int i = 0; i < minLength; i++) {
            if (!indices1.get(i).equals(indices2.get(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * 根据一个路径，提取对应的值，放入values集合
     * @param node 数据对象
     * @param pathParts 路径数组
     * @param index 本次要取的路径位于数组中的索引位置
     * @param values 存放值的集合
     */
    private static void extractValuesRecursive(Object node, String[] pathParts, int index, List<PathValue> values, List<Integer> currentIndices) {
        if (node == null || index >= pathParts.length) {
            if (node != null) {
                values.add(new PathValue(node, currentIndices));
            }
            return;
        }

        String part = pathParts[index];
        boolean isArrayPath = part.contains("[*]");
        part = part.replace("[*]", "");

        if (node instanceof JSONObject) {
            JSONObject jsonObj = (JSONObject) node;
            Object child = jsonObj.get(part);

            if (child instanceof JSONArray && isArrayPath) {
                JSONArray array = (JSONArray) child;
                for (int i = 0; i < array.size(); i++) {
                    List<Integer> newIndices = new ArrayList<>(currentIndices);
                    newIndices.add(i);
                    extractValuesRecursive(array.get(i), pathParts, index + 1, values, newIndices);
                }
            } else {
                extractValuesRecursive(child, pathParts, index + 1, values, currentIndices);
            }
        } else if (node instanceof JSONArray) {
            JSONArray array = (JSONArray) node;
            for (int i = 0; i < array.size(); i++) {
                List<Integer> newIndices = new ArrayList<>(currentIndices);
                newIndices.add(i);
                Object element = array.get(i);

                if (isArrayPath && element instanceof JSONObject) {
                    Object child = ((JSONObject) element).get(part);
                    extractValuesRecursive(child, pathParts, index + 1, values, newIndices);
                } else {
                    extractValuesRecursive(element, pathParts, index, values, newIndices);
                }
            }
        }
    }


    // 使用示例
    public static void main11(String[] args) {
        String json = "{\n" +
                "            \"name\": \"John\",\n" +
                "            \"age\": 30,\n" +
                "            \"tags\": [\"aa\", \"bb\", \"cc\"],\n" +
                "            \"addresses\": [\n" +
                "                {\n" +
                "                    \"city\": \"New York\",\n" +
                "                    \"street\": \"Broadway\",\n" +
                "                    \"contacts\": [\n" +
                "                        {\n" +
                "                            \"type\": \"phone\",\n" +
                "                            \"value\": \"123456\"\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"type\": \"phone2\",\n" +
                "                            \"value\": \"789987\"\n" +
                "                        }\n" +
                "                    ]\n" +
                "                },\n" +
                "                {\n" +
                "                    \"city\": \"Boston\",\n" +
                "                    \"street\": \"Main St\",\n" +
                "                    \"contacts\": [\n" +
                "                        {\n" +
                "                            \"type\": \"email\",\n" +
                "                            \"value\": \"test@test.com\"\n" +
                "                        }\n" +
                "                    ]\n" +
                "                }\n" +
                "            ]\n" +
                "        }";

        // 1. 转换成树结构
        JsonTreeNode tree = parseJsonToTree(json);
        printTree(tree, 0);

        // 定义要提取的路径
        Map<String, String> paths = new HashMap<>();
        paths.put("$.name", "$.name");
        paths.put("$.tags", "$.tags");  // 不带 [*]，将整个数组作为一个值
        paths.put("$.addresses[*].city", "$.addresses[*].city");  // 带 [*]，遍历数组
        paths.put("$.addresses[*].contacts[*].type", "$.addresses[*].contacts[*].type");  // 不带 [*]，将整个 contacts 数组作为一个值
        paths.put("$.addresses[*].contacts[*].value", "$.addresses[*].contacts[*].value");  // 带 [*]，遍历数组
//        paths.put("name", "$.name");
//        paths.put("tags", "$.tags");  // 不带 [*]，将整个数组作为一个值
//        paths.put("city", "$.addresses[*].city");  // 带 [*]，遍历数组
//        paths.put("contactsType", "$.addresses[*].contacts[*].type");  // 不带 [*]，将整个 contacts 数组作为一个值
//        paths.put("contactValue", "$.addresses[*].contacts[*].value");  // 带 [*]，遍历数组

        // 提取值并转换为JSON数组
        JSONArray result = extractValuesToJsonArray(json, paths);

        // 美化输出
        System.out.println("Result JSON Array:");
        System.out.println(JSONUtil.toJsonPrettyStr(result));
    }

    private static void printTree(JsonTreeNode node, int level) {
        String indent = "  ";
        System.out.println(indent + "Key: " + node.getKey());
        System.out.println(indent + "Path: " + node.getPath());
        System.out.println(indent + "Value: " + node.getValue());
        System.out.println(indent + "IsArray: " + node.isArray());
        for (JsonTreeNode child : node.getChildren()) {
            printTree(child, level + 1);
        }
    }







    /**
     * 根据路径和值构建JSON
     * @param pathValues 路径和值的映射，路径格式如："$.name", "$.addresses[0].city"
     * @return 构建好的JSON对象
     */
    public static JSONObject buildJson(Map<String, Object> pathValues) {
        JSONObject root = new JSONObject();

        for (Map.Entry<String, Object> entry : pathValues.entrySet()) {
            String path = entry.getKey().replaceFirst("\\$\\.", "");
            Object value = entry.getValue();
            setValueByPath(root, path, value);
        }

        return root;
    }

    private static void setValueByPath(JSONObject root, String path, Object value) {
        String[] parts = path.split("\\.");
        JSONObject current = root;

        for (int i = 0; i < parts.length - 1; i++) {
            String part = parts[i];
            String[] arrayParts = parseArrayPath(part);
            String key = arrayParts[0];
            Integer index = arrayParts[1] != null ? Integer.parseInt(arrayParts[1]) : null;

            if (index != null) {
                // 处理数组路径
                JSONArray array;
                if (!current.containsKey(key)) {
                    array = new JSONArray();
                    current.set(key, array);
                } else {
                    array = current.getJSONArray(key);
                }
                // 确保数组有足够的大小
                while (array.size() <= index) {
                    array.add(new JSONObject());
                }
                current = array.getJSONObject(index);
            } else {
                // 处理对象路径
                JSONObject next;
                if (!current.containsKey(key)) {
                    next = new JSONObject();
                    current.set(key, next);
                } else {
                    next = current.getJSONObject(key);
                }
                current = next;
            }
        }

        // 处理最后一个部分
        String lastPart = parts[parts.length - 1];
        String[] arrayParts = parseArrayPath(lastPart);
        String key = arrayParts[0];
        Integer index = arrayParts[1] != null ? Integer.parseInt(arrayParts[1]) : null;

        if (index != null) {
            // 最后一个是数组索引
            JSONArray array;
            if (!current.containsKey(key)) {
                array = new JSONArray();
                current.set(key, array);
            } else {
                array = current.getJSONArray(key);
            }
            while (array.size() <= index) {
                array.add(null);
            }
            array.set(index, value);
        } else {
            // 普通键值
            current.set(key, value);
        }
    }

    /**
     * 解析可能包含数组索引的路径部分
     * @return [key, index] 如果没有索引，index为null
     */
    private static String[] parseArrayPath(String part) {
        if (part.contains("[") && part.endsWith("]")) {
            int start = part.indexOf("[");
            String key = part.substring(0, start);
            String index = part.substring(start + 1, part.length() - 1);
            return new String[]{key, index};
        }
        return new String[]{part, null};
    }

    // 使用示例
    public static void main(String[] args) {
        // 示例1：简单对象
        Map<String, Object> pathValues1 = new HashMap<>();
        pathValues1.put("$.name", "John");
        pathValues1.put("$.age", 30);
        pathValues1.put("$.tags", new String[]{"aa", "bb", "cc"});

        JSONObject result1 = buildJson(pathValues1);
        System.out.println("Simple Object:");
        System.out.println(JSONUtil.toJsonPrettyStr(result1));

//        // 示例2：复杂嵌套对象
//        Map<String, Object> pathValues2 = new HashMap<>();
//        pathValues2.put("$.name", "John");
//        pathValues2.put("$.addresses[0].city", "New York");
//        pathValues2.put("$.addresses[0].contacts[0].type", "phone");
//        pathValues2.put("$.addresses[0].contacts[0].value", "123456");
//        pathValues2.put("$.addresses[1].city", "Boston");
//        pathValues2.put("$.addresses[1].contacts[0].type", "email");
//        pathValues2.put("$.addresses[1].contacts[0].value", "test@test.com");
//
//        JSONObject result2 = buildJson(pathValues2);
//        System.out.println("\nComplex Object:");
//        System.out.println(JSONUtil.toJsonPrettyStr(result2));
//        HtUtil.getId();
    }
}
